package service

import (
	"os/signal"
	"syscall"
	"time"

	"gitee.com/night-tc/gobige/entity"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/serverMgr"
	"gitee.com/night-tc/gobige/sess"
	"gitee.com/night-tc/gobige/timerwheel"
)

/*
后代service接口
*/
type IServiceReal interface {
	global.IsrvInst
	entity.IEntities
	sess.INetServer
	timerwheel.ITimer
	serverMgr.IExt

	/* 生命周期 */
	//所有子系统的初始化
	Init() error
	//循环调用
	Loop()
	//循环调用中间
	Looping()
	//循环调用结尾
	Looped()
	//结束服务
	Destroy()

	/* 公共函数 */

	//监听需要主动连接的服务器逻辑
	WatchServer()
	// 服务器连接断开
	OnServerSessDisconnect(sid uint64)
	// 服务器连接成功
	OnServerSessConnect(srvid uint64, srvtype global.ServerTypeEnum)
}

//////////////////////////////////////////////////////////////
/* 生命周期 */

// 所有子系统的初始化
func (this *Service) Init() (err error) {
	//注册消息处理
	this.RegMsgProc(&Service_Proc{this})

	signal.Notify(this.closeC, syscall.SIGINT, syscall.SIGTERM)

	if err = this.Entities.Init(); err != nil {
		return err
	}
	if err = this.DisMgr.Start(); err != nil {
		return err
	}
	this.Timer.Start()
	if err = this.NetSrv.Start(); err != nil {
		return err
	}
	this.real.WatchServer()
	this.Etcd.Start()
	// 检查是否需要自动关服
	this.Timer.LoopTimer(10*time.Second, this.CheckClose)
	return nil
}

// 循环调用
func (this *Service) Loop() {
	this.Timer.OnTick(this.NowTime.Load())
}

// 循环调用中间
func (this *Service) Looping() {
	this.Entities.Loop()

}

// 循环调用结尾
func (this *Service) Looped() {
	this.DelayCallHost.Exec()
}

// 结束服务
func (this *Service) Destroy() {
	logger.Info("Service Destroy")
	this.Entities.Destroy()
	this.Etcd.Close()
	this.NetSrv.Stop()
	this.Timer.Stop()
	this.thgo.CloseWait()
}

/* 生命周期 */
//////////////////////////////////////////////////////////////
/* 公共函数 */

//
/*
监听需要主动连接的服务器逻辑
做服发现一般有二个目的：
	   1、主动连接对方服务器；
	   2、管理用户去对应服务器时候，使用什么负载均衡的逻辑；
	   默认系统给他们分配的都是随机负载均衡器；
	   如果你想修改，可以重载这个函数；
	   同一个stype+groupid的key只能watch一次；
	   所以上层使用新的负载均衡器Watch之后，这里就不会重新Watch了
*/
func (this *Service) WatchServer() {

	for _, stype := range this.Sinfo.ConSrvTypeList {
		this.DisMgr.Watch(stype, this.Sinfo.GroupID, nil)
	}
	for _, stype := range this.Sinfo.WatchSrvTypeList {
		this.DisMgr.Watch(stype, this.Sinfo.GroupID, nil)
	}
	for _, stype := range this.Sinfo.OthConSrvTypeList {
		this.DisMgr.Watch(stype, this.Sinfo.OthGroupID, nil)
	}
	for _, stype := range this.Sinfo.OthWatchSrvTypeList {
		this.DisMgr.Watch(stype, this.Sinfo.OthGroupID, nil)
	}
}

// 服务器连接断开
func (this *Service) OnServerSessDisconnect(sid uint64) {
	if this.GetClientSess(sid) != nil {
		return
	}
	/*
		这个链接断开了，需要处理一下
	*/
	logger.Warnf("Server disconnected sid:%d", sid)
	this.Entities.RangeByType(entity.Entity_Type_Player, func(k, v any) bool {
		if p, ok := v.(entity.IEntityReal); ok {
			if p.IsExistSID(sid) {
				_ = this.DestroyEntity(p.GetEntityID())
			}
		}
		return true
	})
}

// 服务器连接成功
func (this *Service) OnServerSessConnect(srvid uint64, srvtype global.ServerTypeEnum) {
	/*
		连接成功后，可以根据类型做一些处理
		比如去中心服务器同步一些全局数据
	*/
	logger.Infof("Server connected srvid:%d,srvtype:%d", srvid, srvtype)
}

/* 公共函数 */
//////////////////////////////////////////////////////////////
/* sess.INetServer */

// 遍历所有被动连接，返回false就退出遍历
func (this *Service) RangeSess(f func(sess sess.INetSess) bool) {
	outok := true
	this.clientSesses.Range(func(key, value any) bool {
		outok = f(value.(sess.INetSess))
		return outok
	})
	if !outok {
		return
	}
	this.NetSrv.RangeSess(f)
}

// 获取会话
func (this *Service) GetClientSess(id uint64) (result *sess.NetSess) {
	if v, ok := this.clientSesses.Load(id); ok {
		result = v.(*sess.NetSess)
	} else {
		result = this.NetSrv.GetClientSess(id)
	}
	return
}

/* sess.INetServer */
//////////////////////////////////////////////////////////////
/* entity.ITime */

// Loop时的时间
func (this *Service) GetNowTime() time.Time {
	return this.NowTime.Load()
}

/* entity.ITime */
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
